/**
 * @author: sundx
 * @date: 2020-05-10 04:03:31
 * @Last Modified by: sundx
 * @Last Modified time: 2020-05-11 15:18:21
 */
#include "http_server_test.h"
namespace sdx {
HttpServer::HttpServer() {
  std::cout << "http server construct..." << std::endl;
}
HttpServer::~HttpServer() {
  std::cout << "http server construct..." << std::endl;
}
void HttpServer::replyContent() {
  int checkedIndex = 0;                       //已分析的字节数
  int readIndex = 0;                          //已读取的字节数
  int dataRecv = 0;                           //已经收到的字符数
  int startLine = 0;                          //行在buffer中的起始位置
  memset(httpClientBuff, '\0', MESSAGE_SIZE); //初始化接收buff
  CHECK_STATE checkState = CHECK_REQUEST_LINE;
  while (true) {
    dataRecv = recv(getAcceptFd(), httpClientBuff + readIndex,
                    MESSAGE_SIZE - readIndex, 0); //接收数据，但是不覆盖；
    if (dataRecv == -1) {
      std::cout << "reading failed\n" << std::endl;
      break;
    } else if (dataRecv == 0) {
      std::cout << "remote client has closed the connection\n" << std::endl;
      break;
    }
    readIndex += dataRecv;
    HTTP_CODE result = parseContent(httpClientBuff, checkedIndex, checkState,
                                    readIndex, startLine);
    if (result == NO_REQUEST) {
      continue;
    } else if (result == GET_REQUEST) {
      send(getAcceptFd(), reply2client[0], sizeof(reply2client[0]), 0);
      // const char *filename = "test.html";
      // int openfile = open(filename, O_RDONLY);
      // struct stat sat_buff;
      // fstat(openfile, &sat_buff);
      // sendfile(getAcceptFd(), openfile, NULL, &sat_buff.st_size);
      break;
    } else {
      send(getAcceptFd(), reply2client[1], sizeof(reply2client[1]), 0);
      break;
    }
  }
}
HTTP_CODE HttpServer::parseContent(char *httpClientBuff, int &checkedIndex,
                                   CHECK_STATE &checkState, int &readIndex,
                                   int &startline) {
  LINE_STATE lineState = LINE_OK;
  HTTP_CODE retCode = NO_REQUEST;
  while ((lineState = parseLine(httpClientBuff, checkedIndex, readIndex)) ==
         LINE_OK) {
    char *temp = httpClientBuff + startline;
    startline = checkedIndex;
    switch (checkState) {
    case CHECK_REQUEST_LINE:
      retCode = parseRequesetLine(temp, checkState);
      if (retCode == BAD_REQUEST)
        return BAD_REQUEST;
      break;
    case CHECK_HEADERS:
      retCode = parseHeaders(temp);
      if (retCode == BAD_REQUEST) {
        return BAD_REQUEST;
      } else if (retCode == GET_REQUEST) {
        return GET_REQUEST;
      }
      break;
    default:
      return INTERNAL_ERROR;
      break;
    }
  }
  if (lineState == LINE_OPEN)
    return NO_REQUEST;
  else
    return BAD_REQUEST;
}

// 从状态机，表示解析一行
LINE_STATE HttpServer::parseLine(char *httpClientBuff, int &checkedIndex,
                                 int &readIndex) {
  // checkIndex指向buffer的正在分析的字节，readIndex指向buffer尾后
  //即从0~checkIndex是已分析完毕，checkIndex~readIndex-1待分析
  char temp;
  for (; checkedIndex < readIndex; ++checkedIndex) {
    temp = httpClientBuff[checkedIndex];
    //如果当前是回车符，则说明可能读取到了一个完整行
    //如果是'\n'，即换行符，也说明可能读取到了一个完整行
    if (temp == '\r') {
      //如果当前是本行最后一个字符，则说明不完整，需要更多数据
      //如果下一个字符是'\n'则说明读取到了完整的行
      //否则说明HTTP请求存在语法问题
      if ((checkedIndex + 1) == readIndex) {
        return LINE_OPEN;
      } else if (httpClientBuff[checkedIndex + 1] == '\n') {
        httpClientBuff[checkedIndex++] = '\0';
        httpClientBuff[checkedIndex++] = '\0';
        return LINE_OK;
      } else {
        return LINE_BAD;
      }
    } else if (temp == '\n') {
      if (httpClientBuff[checkedIndex - 1] == '\r') {
        httpClientBuff[checkedIndex - 1] = '\0';
        httpClientBuff[checkedIndex++] = '\0';
        return LINE_OK;
      } else {
        return LINE_BAD;
      }
    }
  }
  return LINE_OPEN;
}
HTTP_CODE HttpServer::parseRequesetLine(char *temp, CHECK_STATE &checkState) {
  /** 头部示例：
   * Get http://www.baiducom/index.html Http/1.0
   * User-Agent: wget/1.12 (linux-gnu)
   * Host: www.baidu.com
   * Connection: close
   */
  //如果请求行中没有空格和'\t'字符则说明HTTP请求有问题
  // strpbrk返回前面缓冲区第一个在后面字符集合中的字符位置
  char *url = strpbrk(temp, " \t");
  if (!url)
    return BAD_REQUEST;
  *url++ = '\0';
  // strcasecmp与strcmp的区别就是不区分大小写
  char *requestMethod = temp;
  if (strcasecmp(requestMethod, "GET") == 0) {
    std::cout << "The request method is GET" << std::endl;
  } else {
    std::cout << "Only parse GET request...\n" << std::endl;
    return BAD_REQUEST;
  }
  // strspn函数统计缓冲区前面多少个连续字符在字符集合中
  //该函数返回 str1 中第一个不在字符串 str2
  //中出现的字符下标。即第一个不是'\t'的位置
  url += strspn(url, " \t");
  char *version = strpbrk(url, " \t");
  if (!version) {
    return BAD_REQUEST;
  }
  *version++ = '\0';
  version += strspn(version, " \t");
  // 对于非http/1.1的处理，strchr 是在char*中匹配第一个与后面char相同的位置，
  // if (strcasecmp(version, "HTTP/1.1") != 0) {
  //   url += 7;
  //   url = strchr(url, '/');
  // }
  if (!url || url[0] != '/')
    return BAD_REQUEST;
  checkState = CHECK_HEADERS;
  return NO_REQUEST;
}
HTTP_CODE HttpServer::parseHeaders(char *temp) {
  if (temp[0] == '\0') {
    return GET_REQUEST;
  } else if ((strncasecmp(temp, "HOST:", 5)) == 0) {
    temp += 5;
    temp += strspn(temp, " \t");
    std::cout << "the host is " << temp << std::endl;
  } else {
    std::cout << "can not handle this header" << std::endl;
  }
  return NO_REQUEST;
}
} // namespace sdx
